// 引入 React 的钩子：状态管理、副作用、缓存函数
import {useState, useEffect, useCallback} from 'react';
// 引入自定义的类型定义
import {Position, GameState} from '../types';

// 游戏网格大小（20×20）
const GRID_SIZE = 20;
// 贪吃蛇初始位置（中央）
const INITIAL_SNAKE = [{x: 10, y: 10}];
// 食物初始位置
const INITIAL_FOOD = {x: 15, y: 15};

// 自定义 Hook：封装贪吃蛇游戏逻辑
export const useSnakeGame = () => {
    // 游戏状态：蛇、食物、方向、分数、结束标记、运行标记
    const [gameState, setGameState] = useState<GameState>({
        snake: INITIAL_SNAKE,
        food: INITIAL_FOOD,
        direction: 'RIGHT',
        score: 0,
        gameOver: false,
        isPlaying: false
    });

    /**
     * 生成新的食物
     * 随机坐标，并确保不会出现在蛇身上
     */
    const generateFood = useCallback((snake: Position[]): Position => {
        let newFood: Position;
        do {
            newFood = {
                x: Math.floor(Math.random() * GRID_SIZE),
                y: Math.floor(Math.random() * GRID_SIZE)
            };
        } while (snake.some(segment => segment.x === newFood.x && segment.y === newFood.y));
        return newFood;
    }, []);

    /**
     * 移动蛇：根据当前方向计算新头部坐标，检测碰撞与吃食物
     */
    const moveSnake = useCallback(() => {
        setGameState(prevState => {
            // 游戏结束或未开始时不移动
            if (prevState.gameOver || !prevState.isPlaying) return prevState;

            const {snake, direction, food} = prevState;
            const head = snake[0];
            const newHead: Position = {...head};

            // 根据方向计算新头部位置（循环边界）
            switch (direction) {
                case 'UP':
                    newHead.y = (newHead.y - 1 + GRID_SIZE) % GRID_SIZE;
                    break;
                case 'DOWN':
                    newHead.y = (newHead.y + 1) % GRID_SIZE;
                    break;
                case 'LEFT':
                    newHead.x = (newHead.x - 1 + GRID_SIZE) % GRID_SIZE;
                    break;
                case 'RIGHT':
                    newHead.x = (newHead.x + 1) % GRID_SIZE;
                    break;
            }

            // 检测是否撞到自己
            if (snake.some(segment => segment.x === newHead.x && segment.y === newHead.y)) {
                return {...prevState, gameOver: true, isPlaying: false};
            }

            // 新蛇身：头部插入，尾部视情况删除
            const newSnake = [newHead, ...snake];
            let newFood = food;
            let newScore = prevState.score;

            // 如果吃到食物
            if (newHead.x === food.x && newHead.y === food.y) {
                newFood = generateFood(newSnake); // 生成新食物
                newScore += 10;                   // 分数 +10
            } else {
                newSnake.pop(); // 否则去掉尾部，保持长度
            }

            return {
                ...prevState,
                snake: newSnake,
                food: newFood,
                score: newScore
            };
        });
    }, [generateFood]);

    /**
     * 改变蛇的移动方向
     * 不允许直接反向（例如正在向右不能直接向左）
     */
    const changeDirection = useCallback((newDirection: GameState['direction']) => {
        setGameState(prevState => {
            // 防止倒车时撞到自身
            const opposites = {
                'UP': 'DOWN',
                'DOWN': 'UP',
                'LEFT': 'RIGHT',
                'RIGHT': 'LEFT'
            };

            if (opposites[newDirection] === prevState.direction) {
                return prevState; // 忽略反向指令
            }

            return {...prevState, direction: newDirection};
        });
    }, []);

    /**
     * 开始/重置游戏
     */
    const startGame = useCallback(() => {
        setGameState({
            snake: INITIAL_SNAKE,
            food: generateFood(INITIAL_SNAKE),
            direction: 'RIGHT',
            score: 0,
            gameOver: false,
            isPlaying: true
        });
    }, [generateFood]);

    /**
     * 暂停游戏
     */
    const pauseGame = useCallback(() => {
        setGameState(prevState => ({...prevState, isPlaying: false}));
    }, []);

    /**
     * 恢复游戏（仅在未结束时）
     */
    const resumeGame = useCallback(() => {
        setGameState(prevState => ({...prevState, isPlaying: !prevState.gameOver}));
    }, []);

    // 暴露给组件使用的数据和方法
    return {
        gameState,
        moveSnake,
        changeDirection,
        startGame,
        pauseGame,
        resumeGame,
        GRID_SIZE
    };
};
